#include "vl_message_queue.h"

using namespace VL;


/**
 * @Author: CimZzz
 * @Date: 2022-07-15 11:57:11
 * 
 * 构造方法
 * 
 * @param dataPtr 数据指针
 * @param dataLength 数据长度
 * @param typeCode 类型码
 * @param syncCode 同步码
 */
VLMessageQueueData::VLMessageQueueData(std::shared_ptr<void> dataPtr, unsigned int dataLength, unsigned int typeCode, unsigned int syncCode): dataPtr(dataPtr), dataLength(dataLength), typeCode(typeCode), syncCode(syncCode) {
}

/**
 * @Author: CimZzz
 * @Date: 2022-07-15 16:53:12
 * 
 * 判断当前数据是否为空
 * @return 如果为空返回 ture
 */
bool VLMessageQueueData::isEmpty() {
	return this->dataLength == 0 || this->dataPtr.get() == nullptr;
}

/**
 * @Author: CimZzz
 * @Date: 2022-07-14 18:51:20
 * 
 * 获取数据指针
 * 
 * @return 数据指针
 */
std::shared_ptr<void> VLMessageQueueData::getData() const {
	return this->dataPtr;
}


/**
 * @Author: CimZzz
 * @Date: 2022-07-15 16:41:06
 * 
 * 获取数据长度
 * 
 * @return 数据长度
 */
unsigned int VLMessageQueueData::getDataLength() const {
	return this->dataLength;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-25 07:58:38
 * 
 * 获取类型码
 * 
 * @return 类型码
 */
unsigned int VLMessageQueueData::getTypeCode() const {
	return this->typeCode;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-28 13:18:20
 * 
 * 获取同步码
 * 
 * @return 同步码
 */
unsigned int VLMessageQueueData::getSyncCode() const {
	return this->syncCode;
}

/**
 * @Author: CimZzz
 * @Date: 2022-07-15 16:55:21
 * 
 * 空消息队列数据
 */
std::shared_ptr<VLMessageQueueData> VLMessageQueue::EMPTY(nullptr);

/**
 * @Author: CimZzz
 * @Date: 2022-07-15 16:36:10
 * 
 * 构造方法
 */
VLMessageQueue::VLMessageQueue(): isDestroy(false), isEnqueueable(true)  {
}

/**
 * @Author: CimZzz
 * @Date: 2022-07-15 16:48:38
 * 
 * 析构方法
 */
VLMessageQueue::~VLMessageQueue() {
	destroy();
}

/**
 * @Author: CimZzz
 * @Date: 2022-07-15 16:50:25
 * 
 * 入队数据
 * @param dataPtr 消息队列数据指针
 */
void VLMessageQueue::enqueue(VLMessageQueueData* dataPtr) {
	{
		std::lock_guard<std::mutex> locker(this->mutex);
		if(this->isDestroy || !this->isEnqueueable) {
			return;
		}
		this->queue.push_back(std::shared_ptr<VLMessageQueueData>(dataPtr));
	}
	// 唤醒一个条件变量
	this->cond.notify_one();
}

/**
 * @Author: CimZzz
 * @Date: 2022-07-15 16:51:28
 * 
 * 入队数据
 * @param dataPtr 消息队列数据指针
 */
void VLMessageQueue::enqueue(std::shared_ptr<VLMessageQueueData> dataPtr) {
	{
		std::lock_guard<std::mutex> locker(this->mutex);
		if(this->isDestroy || !this->isEnqueueable) {
			return;
		}
		this->queue.push_back(std::shared_ptr<VLMessageQueueData>(dataPtr));
	}
	// 唤醒一个条件变量
	this->cond.notify_one();
}

/**
 * @Author: CimZzz
 * @Date: 2022-07-15 16:50:25
 * 
 * 入队数据, 插入到队首
 * @param dataPtr 消息队列数据指针
 */
void VLMessageQueue::enqueueFirst(VLMessageQueueData* dataPtr) {
	{
		std::lock_guard<std::mutex> locker(this->mutex);
		if(this->isDestroy || !this->isEnqueueable) {
			return;
		}
		this->queue.push_front(std::shared_ptr<VLMessageQueueData>(dataPtr));
	}
	// 唤醒一个条件变量
	this->cond.notify_one();
}

/**
 * @Author: CimZzz
 * @Date: 2022-07-15 16:51:28
 * 
 * 入队数据, 插入到队首
 * @param dataPtr 消息队列数据指针
 */
void VLMessageQueue::enqueueFirst(std::shared_ptr<VLMessageQueueData> dataPtr) {
	{
		std::lock_guard<std::mutex> locker(this->mutex);
		if(this->isDestroy || !this->isEnqueueable) {
			return;
		}
		this->queue.push_front(std::shared_ptr<VLMessageQueueData>(dataPtr));
	}
	// 唤醒一个条件变量
	this->cond.notify_one();
}

/**
 * @Author: CimZzz
 * @Date: 2022-07-15 16:52:24
 * 
 * 出队数据
 * @return 消息队列数据指针
 * 
 * @attention 该方法不会导致阻塞, 如果不存在数据则会返回空消息队列数据
 */
std::shared_ptr<VLMessageQueueData> VLMessageQueue::dequeue() {
	std::lock_guard<std::mutex> locker(this->mutex);
	if(this->isDestroy) {
		return VLMessageQueue::EMPTY;
	}
	if(this->queue.empty()) {
		return VLMessageQueue::EMPTY;
	}
	auto front = this->queue.front();
	this->queue.pop_front();
	return front;
}


/**
 * @Author: CimZzz
 * @Date: 2022-07-15 16:55:56
 * 
 * 出队数据
 * 
 * @param waitTime 等待时间, 单位毫秒
 * 
 * @return 消息队列数据指针
 * 
 * @attention 如果当前消息队列中无数据, 则会一直阻塞直至收到数据
 * @attention 如果等待时间大于 0, 则会在等待超时后尝试获取, 如果不存在数据返回空消息队列数据
 */
std::shared_ptr<VLMessageQueueData> VLMessageQueue::dequeueBlock(unsigned int waitTime) {
	std::unique_lock<std::mutex> locker(this->mutex);
	if(this->isDestroy) {
		return VLMessageQueue::EMPTY;
	}

	if(this->queue.empty()) {
		if(waitTime == 0) {
			this->cond.wait(locker);
		} else {
			this->cond.wait_for(locker, std::chrono::milliseconds(waitTime));
		}
	}


	if(this->queue.empty()) {
		return VLMessageQueue::EMPTY;
	}

	auto front = this->queue.front();
	this->queue.pop_front();
	return front;
}


/**
 * @Author: CimZzz
 * @Date: 2022-08-26 12:44:20
 * 
 * 设置当前是否可以入队消息
 * 
 * @param isEnqueueable 如果为 true 表示当前可以入队消息
 */
void VLMessageQueue::setEnqueueable(bool isEnqueueable) {
	this->isEnqueueable = isEnqueueable;
}

/**
 * @Author: CimZzz
 * @Date: 2022-08-26 13:49:38
 * 
 * 唤醒等待的消息队列, 如果当前队列中不存在数据返回空指针
 */
void VLMessageQueue::notifyAll() {
	// 唤醒一个条件变量
	this->cond.notify_all();
}

/**
 * @Author: CimZzz
 * @Date: 2022-07-15 17:07:21
 * 
 * 清空消息队列数据
 */
void VLMessageQueue::clear() {
	std::lock_guard<std::mutex> locker(this->mutex);
	if(this->isDestroy) {
		return;
	}
	std::deque<std::shared_ptr<VLMessageQueueData>> emptyQueue;
	this->queue.swap(emptyQueue);
}


/**
 * @Author: CimZzz
 * @Date: 2022-07-15 17:09:26
 * 
 * 销毁消息队列, 与清空消息队列不同的是
 * 一旦消息队列销毁, 将不会再接收新的消息数据, 并且全部阻塞将会被唤醒返回空
 */
void VLMessageQueue::destroy() {
	{
		std::lock_guard<std::mutex> locker(this->mutex);
		if(this->isDestroy) {
			return;
		}
		std::deque<std::shared_ptr<VLMessageQueueData>> emptyQueue;
		this->queue.swap(emptyQueue);
		this->isDestroy = true;
	}
	this->cond.notify_all();
}